from flask import Blueprint, g
from flask_restful import Api, Resource, fields, marshal_with, reqparse, marshal

from apps.models.news_model import NewsType, News
from apps.models.user_model import User
from apps.util import login_required
from exts import db

news_bp = Blueprint('news', __name__)
api = Api(news_bp)


# 输出格式
types_fields = {
    'id': fields.Integer,
    'name': fields.String(attribute='type_name')
}

# 添加传入
type_parser = reqparse.RequestParser()
type_parser.add_argument('typeName', type=str, required=True, help='必须添加新闻分类名字', location='form')

# 修改传入
update_type_parser = type_parser.copy()
update_type_parser.add_argument('id', type=int, required=True, help='必须添加要修改的分类id')

# 删除传入
delete_type_parser = reqparse.RequestParser()
delete_type_parser.add_argument('id', type=int, required=True, help='必须添加要删除的分类id')


# 新闻类型 #5失效的功能级授权
class NewsTypeApi(Resource):
    @login_required
    @marshal_with(types_fields)
    def get(self):
        types = NewsType.query.all()
        return types

    # 添加新的新闻类型
    @login_required
    def post(self):  # 需要传入名字 必须在body下form表单添加
        user = User.query.filter_by(username=g.user.username).first()
        if (user.user_authority != 1):
            data = {
                'status': 500,
                'mas': '您权限不足',
            }
            return data
        else:
            pass
        args = type_parser.parse_args()
        typeName = args.get('typeName')
        # 数据库的添加
        newsType = NewsType()
        newsType.type_name = typeName
        db.session.add(newsType)
        db.session.commit()
        return marshal(newsType, types_fields)

    # 修改分类名称
    @login_required
    def patch(self):
        user = User.query.filter_by(username=g.user.username).first()
        if(user.user_authority != 1):
            data = {
                'status': 500,
                'mas': '您权限不足',
            }
            return data
        else:
            pass
        # 获取传入的值
        args = update_type_parser.parse_args()
        typeId = args.get('id')
        new_type_name = args.get('typeName')
        # 数据库查找
        type_obj = NewsType.query.get(typeId)
        if type_obj:
            type_obj.type_name = new_type_name
            db.session.commit()

            data = {
                'status': 200,
                'mas': '修改成功',
                'type': marshal(type_obj, types_fields)
            }
        else:
            data = {
                'status': 400,
                'mas': '类型查找失败',
            }
        return data

    # 删除分类名称
    @login_required
    def delete(self):
        user = User.query.filter_by(id =g.user.id).first()
        if(user.user_authority != 1):
            data = {
                'status': 500,
                'mas': '您权限不足',
            }
            return data
        else:
            pass
        args = delete_type_parser.parse_args()
        typeId = args.get('id')
        type_obj = NewsType.query.get(typeId)
        if type_obj:
            db.session.delete(type_obj)
            db.session.commit()
            data = {
                'status': 200,
                'mas': '删除成功'
            }
        else:
            data = {
                'status': 400,
                'mas': '类型查找失败'
            }
        return data


class AuthorName(fields.Raw):
    def format(self, value):
        return value.username


# 传入
news_parser = reqparse.RequestParser()
news_parser.add_argument('typeid', type=int, help='必须添加新闻类型id', required=True)
news_parser.add_argument('page', type=int)

# 输出格式
'''
{
 'has_more':true,
 'data':[],
 'return_count':8,
 'html':null
}
'''
#


class AuthorName(fields.Raw):
    def format(self, value):
        return value.username


# 每条新闻格式
news_fields = {
    'id': fields.Integer,
    'title': fields.String,
    'desc': fields.String,
    'datetime': fields.DateTime(attribute='date_time'),
    'author': AuthorName(attribute='author'),
    'url': fields.Url('news.newsdetail', absolute=True)  # 点击后得到详情新闻内容
}


# 新闻api  看详情
class NewsListApi(Resource):
    # 某新闻分类下所有新闻
    def get(self):  # 获取新闻
        args = news_parser.parse_args()
        typeid = args.get('typeid')
        # newstype = NewsType.query.get(typeid)
        page = args.get('page', 1)
        pagination = News.query.filter(News.news_type_id == typeid).paginate(page=page, per_page=8)  # 4.资源缺乏或速率限制
        data = {
                'has_more': pagination.has_next,
                 'data': marshal(pagination.items, news_fields),  # 八个新闻对象
                 'return_count': len(pagination.items),
                 'html': 'null',
                }
        return data


# 回复格式
reply_fields = {
    'user': AuthorName(attribute='user'),
    'content': fields.String,
    'datetime': fields.DateTime(attribute='date_time'),
    'lovenumber': fields.Integer(attribute='love_num')
}

# 评价格式
comment_fields = {
    'user': AuthorName(attribute='user'),
    'content': fields.String,
    'datetime': fields.DateTime(attribute='date_time'),
    'lovenumber': fields.Integer(attribute='love_num'),
    'replys': fields.List(fields.Nested(reply_fields))
}

# 详细格式
news_detail_fields = {
    'id': fields.Integer,
    'title': fields.String,
    'content': fields.String,
    'datetime': fields.DateTime(attribute='date_time'),
    'author': AuthorName(attribute='author'),
    'comments': fields.List(fields.Nested(comment_fields))
}


class NewsDetailApi(Resource):
    @marshal_with(news_detail_fields)
    def get(self, id):  # 获取
        news = News.query.get(id)
        return news

    def post(self):  # 添加
        pass


# 注入漏洞填补  定义新闻传入信息
add_news_parser_new = reqparse.RequestParser()
add_news_parser_new.add_argument('title', type=str, required=True, help='必须填写新闻标题')
add_news_parser_new.add_argument('content', type=str, required=True, help='必须填写新闻内容')
add_news_parser_new.add_argument('typeid', type=int, required=True, help='必须填写新闻类型id')


def pretreat(title, content):  # 8.注入
    new_title = '#标题'+title+'标题#'
    new_content = '#内容'+content+'内容#'
    il_str = ['\'', '\"', '=', 'and', 'exec', 'insert', 'delete', 'update', 'count', '*', '%', 'chr', 'mid', 'truncate', 'daclare']
    tip = True
    for s in il_str:
        if s in new_title or s in new_content:
            tip = False
    return new_title, new_content, tip


class NewsApi_new(Resource):  # 登录状态下的增删改查
    @login_required
    def post(self):
        c = ''
        args = add_news_parser_new.parse_args()
        title = args.get('title')
        content = args.get('content')
        typeid = args.get('typeid')
        news = News()
        news.title, news.content, tip = pretreat(title, content)
        news.desc = content[:100] + '....'
        news.news_type_id = typeid
        news.user_id = g.user.id
        types = NewsType.query.all()
        for type in types:
            if type.id == typeid:
                c = True
                break
            else:
                pass
        if c == True:
            if tip:
                db.session.add(news)
                db.session.commit()
                data = {
                    'status': 200,
                    'msg': '发布成功',
                    'news': marshal(news, news_detail_fields)
                }
                return data
            else:
                return {'status': 400, 'msg': '可能存在sql注入'}
        else:
            return {'status': 400, 'msg': '新闻类型不存在'}
    def patch(self):
        pass

    def put(self):
        pass

    def delete(self):
        pass


api.add_resource(NewsTypeApi, '/types')  # 状态码200成功 400失败
api.add_resource(NewsListApi, '/newslist')  # 测试时需要传typeid
api.add_resource(NewsDetailApi, '/newsdetail/<int:id>', endpoint='newsdetail')  # 有评论的对应的评论也可返回了,评论的回复也同时返回
api.add_resource(NewsApi_new, '/news_new')  # header Authorization:token
